package tests;

import java.util.Random;

import junit.framework.Assert;
import org.junit.Test;

import command.Invoker;
import command.MoveProcessToMachineCommand;

import model.EnhancedCostEvaluator;
import model.IncrementalCostCalculator;
import model.IncrementalValidator;
import model.Problem;
import model.Solution;
import model.SolverEnvironment;
import solver.LateAcceptanceHeuristicSolver;
import util.Importer;
import util.SolutionImporter;

public class CostEvaluatorTest {

	String[] datasets;
	String[] initial_solutions;
	String[] new_solutions;
	long[] initial_cost;
	long[] new_cost;

	Importer importer;
	Problem problem;
	SolutionImporter solutionImporter;
	Solution solution1;
	Solution solution2;
	EnhancedCostEvaluator ece;
	IncrementalCostCalculator icc;

	public CostEvaluatorTest() {
		datasets = new String[11];
		initial_solutions = new String[11];
		new_solutions = new String[11];
		initial_cost = new long[11];
		new_cost = new long[11];
		datasets[0] = "datasets//model_example.txt";
		initial_solutions[0] = "solutions//assignment_example.txt";
		new_solutions[0] = "solutions//assignment_example_2411.txt";
		initial_cost[0] = 4200l;
		new_cost[0] = 2411l;

		datasets[1] = "datasets//model_a1_1.txt";
		initial_solutions[1] = "solutions//assignment_a1_1.txt";
		new_solutions[1] = "solutions//assignment_a1_1_44306501.txt";
		initial_cost[1] = 49528750l;
		new_cost[1] = 44306501;

		datasets[2] = "datasets//model_a1_2.txt";
		initial_solutions[2] = "solutions//assignment_a1_2.txt";
		new_solutions[2] = "solutions//assignment_a1_2.txt";
		initial_cost[2] = 1061649570l;
		new_cost[2] = 1061649570l;

		datasets[3] = "datasets//model_a1_3.txt";
		initial_solutions[3] = "solutions//assignment_a1_3.txt";
		new_solutions[3] = "solutions//assignment_a1_3.txt";
		initial_cost[3] = 583662270l;
		new_cost[3] = 583662270l;

		datasets[4] = "datasets//model_a1_4.txt";
		initial_solutions[4] = "solutions//assignment_a1_4.txt";
		new_solutions[4] = "solutions//assignment_a1_4.txt";
		initial_cost[4] = 632499600l;
		new_cost[4] = 632499600l;

		datasets[5] = "datasets//model_a1_5.txt";
		initial_solutions[5] = "solutions//assignment_a1_5.txt";
		new_solutions[5] = "solutions//assignment_a1_5.txt";
		initial_cost[5] = 782189690l;
		new_cost[5] = 782189690l;

		datasets[6] = "datasets//model_a2_1.txt";
		initial_solutions[6] = "solutions//assignment_a2_1.txt";
		new_solutions[6] = "solutions//assignment_a2_1.txt";
		initial_cost[6] = 391189190l;
		new_cost[6] = 391189190l;

		datasets[7] = "datasets//model_a2_2.txt";
		initial_solutions[7] = "solutions//assignment_a2_2.txt";
		new_solutions[7] = "solutions//assignment_a2_2.txt";
		initial_cost[7] = 1876768120l;
		new_cost[7] = 1876768120l;

		datasets[8] = "datasets//model_a2_3.txt";
		initial_solutions[8] = "solutions//assignment_a2_3.txt";
		new_solutions[8] = "solutions//assignment_a2_3.txt";
		initial_cost[8] = 2272487840l;
		new_cost[8] = 2272487840l;

		datasets[9] = "datasets//model_a2_4.txt";
		initial_solutions[9] = "solutions//assignment_a2_4.txt";
		new_solutions[9] = "solutions//assignment_a2_4.txt";
		initial_cost[9] = 3223516130l;
		new_cost[9] = 3223516130l;

		datasets[10] = "datasets//model_a2_5.txt";
		initial_solutions[10] = "solutions//assignment_a2_5.txt";
		new_solutions[10] = "solutions//assignment_a2_5.txt";
		initial_cost[10] = 787355300l;
		new_cost[10] = 787355300l;
	}

	@Test
	public void testEvaluator() {
		for (int i = 0; i < datasets.length; i++) {
			importer = new Importer(datasets[i]);
			problem = importer.getProblem();
			importer.readData();
			solutionImporter = new SolutionImporter(problem);
			solutionImporter.setSolutionFileName(initial_solutions[i]);
			solutionImporter.readData();
			solution1 = solutionImporter.getSolution();
			ece = new EnhancedCostEvaluator();
			solutionImporter.setSolutionFileName(new_solutions[i]);
			solutionImporter.readData();
			solution2 = solutionImporter.getSolution();
			ece.setSolutionPair(solution1, solution2);
			ece.computeCost();
			Assert.assertEquals(initial_cost[i], ece.getInitialSolutionCost());
			Assert.assertEquals(new_cost[i], ece.getNewSolutionCost());
		}
	}
	
	@Test
	public void testIncrementalEvaluator() {
		for (int i = 0; i < datasets.length; i++) {
			importer = new Importer(datasets[i]);
			problem = importer.getProblem();
			importer.readData();
			solutionImporter = new SolutionImporter(problem);
			solutionImporter.setSolutionFileName(initial_solutions[i]);
			solutionImporter.readData();
			solution1 = solutionImporter.getSolution();
			icc = new IncrementalCostCalculator();
			solutionImporter.setSolutionFileName(new_solutions[i]);
			solutionImporter.readData();
			solution2 = solutionImporter.getSolution();
			SolverEnvironment env = new SolverEnvironment(problem, solution1, solution2);
			IncrementalCostCalculator icc = env.getCostCalculator();
			Assert.assertEquals(initial_cost[i], icc.getInitialSolutionCost());
			Assert.assertEquals(new_cost[i], icc.getNewSolutionCost());
		}
	}
	
	@Test
	public void testIncrementalEvaluatorDiffCost() {
		for (int i = 0; i < datasets.length; i++) {
			importer = new Importer(datasets[i]);
			problem = importer.getProblem();
			importer.readData();
			solutionImporter = new SolutionImporter(problem);
			solutionImporter.setSolutionFileName(initial_solutions[i]);
			solutionImporter.readData();
			solution1 = solutionImporter.getSolution();
			icc = new IncrementalCostCalculator();
			ece = new EnhancedCostEvaluator();
			solutionImporter.setSolutionFileName(new_solutions[i]);
			solutionImporter.readData();
			solution2 = solutionImporter.getSolution();
			SolverEnvironment env = new SolverEnvironment(problem, solution1, solution2);
			IncrementalCostCalculator icc = env.getCostCalculator();
			IncrementalValidator iv = env.getValidator();
			EnhancedCostEvaluator ece = env.getFullValidator();
			ece.computeCost();
			Assert.assertEquals(initial_cost[i], icc.getInitialSolutionCost());
			Assert.assertEquals(new_cost[i], icc.getNewSolutionCost());
			Assert.assertEquals(ece.getInitialSolutionCost(), icc.getInitialSolutionCost());
			Assert.assertEquals(ece.getNewSolutionCost(), icc.getNewSolutionCost());
			
			int movePid = 1;
			Random random = new Random(100);
			Invoker invoker = new Invoker();
			int start = random.nextInt(problem.M);
			int end = start+problem.M;
			boolean mFound=false;
			int orig_m_index = solution2.getMachineIdForProcessId(movePid);
machines:	for(int m=start; m<end;m++){
				int m_index = m%problem.M;
				if(m_index==orig_m_index)
					continue machines;
				MoveProcessToMachineCommand cmd = new MoveProcessToMachineCommand(ece);
				cmd.setP_id(movePid);
				cmd.setM_id(m_index);
				invoker.addCommand(cmd);
				invoker.executeLastCommand();
				if(!ece.isFeasible()){
					invoker.undoLastCommand();
					continue;
				}
				ece.computeCost();
				long eceCost = ece.getNewSolutionCost();
				ece.printCostAnalysis();
				long iccCost = icc.getCurrentProcessMoveToMachineCost(movePid, m_index);
				Assert.assertEquals(eceCost,iccCost);
				break;
			}			
		}
	}

}
